﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace BovespaMaintainabilityRules
{
    public sealed class ListaRegions : List<Region>
    {
        #region Campos

        private bool _containsRegion;
        private List<LinhaCodigo> _linhasArquivo = null;

        #endregion

        #region Construtor

        public ListaRegions(string arquivo)
            : base()
        {
            string texto = File.ReadAllText(arquivo);
            _containsRegion = texto.Contains("#region");

            List<string> aux = new List<string>(File.ReadAllLines(arquivo));
            _linhasArquivo = new List<LinhaCodigo>();

            for (int i = 0; i < aux.Count; i++)
            {
                _linhasArquivo.Add(new LinhaCodigo(aux[i], i));
            }
        }

        #endregion

        #region Public Methods

        public void CarregaRegions(out Region regionVazia, out LinhaCodigo codigoSemRegion)
        {
            try
            {
                string linha = null;
                int regionsAbertas = 0;
                int classesAbertas = 0;
                int chavesAbertas = 0;
                bool blocoComentario = false;
                bool achouCodigoSemRegion = false;
                bool achouRegionVazia = false;
                bool acabouUsing = false;
                bool contemApenasLinhasVazias = false;
                int itemIndex;
                Region regionAux;

                regionVazia = null;
                codigoSemRegion = null;

                for (int i = 0; i < _linhasArquivo.Count && (!achouCodigoSemRegion || !achouRegionVazia); i++)
                {
                    linha = _linhasArquivo[i].Texto;

                    if (!acabouUsing)
                    {
                        if (linha.Trim().IndexOf("using") == -1)
                        {
                            acabouUsing = true;
                        }
                    }

                    if (_containsRegion)
                    {
                        if (linha.Trim().StartsWith("#")
                            && linha.Contains("region") 
                            && !linha.Contains("endregion")
                            && !blocoComentario
                            && (!linha.Contains("/")
                               || linha.IndexOf("/") > linha.IndexOf("#")))
                        {
                            regionsAbertas++;
                            this.AddInicioRegion(i, linha.IndexOf("#"));

                            contemApenasLinhasVazias = true;
                            continue;
                        }
                        else if (linha.Trim().StartsWith("#")
                                 && linha.Contains("endregion")
                                 && !blocoComentario
                                 && (!linha.Contains("/")
                                     || linha.IndexOf("/") > linha.IndexOf("#")))
                        {
                            itemIndex = this.AddFimRegion(i, linha.IndexOf("#"));

                            regionAux = this[itemIndex];

                            if (contemApenasLinhasVazias)
                                regionVazia = regionAux;

                            regionsAbertas--;
                            continue;
                        }
                        else if(contemApenasLinhasVazias
                                && !String.IsNullOrEmpty(linha.Trim()))
                        {
                            contemApenasLinhasVazias = false;
                        }
                    }

                    if (linha.Contains("/*"))
                    {
                        blocoComentario = true;
                    }

                    if (linha.Contains("class")
                           && !blocoComentario
                           && (!linha.Contains("/")
                          || linha.IndexOf("/") > linha.IndexOf("class")))
                    {
                        classesAbertas++;
                    }
                    else if (linha.Contains("{")
                           && !blocoComentario
                           && (!linha.Contains("/")
                              || linha.IndexOf("/") > linha.IndexOf("{")))
                    {
                        chavesAbertas++;
                    }
                    else if (linha.Contains("}")
                            && !blocoComentario
                            && (!linha.Contains("/")
                           || linha.IndexOf("/") > linha.IndexOf("}")))
                    {
                        chavesAbertas--;

                        if (chavesAbertas == 0)
                            classesAbertas--;
                    }
                    else if (!achouCodigoSemRegion
                             && acabouUsing
                             && !blocoComentario
                             && regionsAbertas == 0
                             && classesAbertas > 0
                             && !String.IsNullOrEmpty(linha)
                             && linha.Trim().IndexOf("//") != 0)
                    {
                        achouCodigoSemRegion = true;
                        codigoSemRegion = _linhasArquivo[i];
                    }

                    if (linha.Contains("*/"))
                    {
                        blocoComentario = false;
                    }
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        #endregion

        #region Private Methods

        private void AddInicioRegion(int linhaComeco, int colunaComeco)
        {
            this.Add(new Region(linhaComeco, colunaComeco));
        }

        private int AddFimRegion(int linhaFim, int colunaFim)
        {
            int itemIndex = -1;

            for (int i = this.Count - 1; i >= 0; i--)
            {
                if (!this[i].LinhaFim.HasValue)
                {
                    this[i].LinhaFim = linhaFim;
                    this[i].ColunaFim = colunaFim;
                    itemIndex = i;
                    break;
                }
            }

            return itemIndex;
        }

        #endregion
    }
}
